#pragma once

#include <vector>
#include <cmath>
#include <iomanip>
#include <functional>
#include <cfloat>
#include "mltree/common/config.h"

namespace MetricSpaceBenchmark::MLIndex::MLTree {

    template<typename T>
    class Point {
    public:
        OID_TYPE oId{0};
        T keyObject{};
        DIS_TYPE dis{DBL_MAX};   // 点到父/枢轴点距离

        Point() = default;

        // 类中的 key 保存传递的 key 的所有数据, 是深度拷贝
        explicit Point(const OID_TYPE id, const T &kO, const DIS_TYPE d = DBL_MAX) : oId(id), keyObject(kO), dis(d) {}

        // 类中的 key 保存传递的 key 的引用地址, 非深度拷贝, 且完美转发: 左值存地址, 右值则转移(深拷贝,原key置空)
        explicit Point(const OID_TYPE id, T &&keyObj, const DIS_TYPE d = DBL_MAX) : oId(id), keyObject(
                std::forward<T>(keyObj)), dis(d) {}

        Point(const Point<T> &other) {
            oId = other.oId;
            keyObject = other.keyObject;
            dis = other.dis;
        }

        Point<T> &operator=(const Point<T> &other) {
            oId = other.oId;
            keyObject = other.keyObject;
            dis = other.dis;
            return *this;
        }

        bool operator==(const Point<T> &other) const noexcept {
            return oId == other.oId && keyObject == other.keyObject && dis == other.dis;
        }

        // 按 oid 升序排序
        bool operator<(const Point<T> &other) const {
            return oId < other.oId;
        }

        DIS_TYPE distance(const Point<T> &otherPoint) const {
            return keyObject.distance(otherPoint.keyObject);
        }
    };

    // 自定义哈希函数
    template<typename T>
    class PointHash {
    public:
        size_t operator()(const Point<T> &p) const {  // 必须添加 const
            size_t seed = std::hash<OID_TYPE>{}(p.oId);
            seed ^= std::hash<T>{}(p.keyObject) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
            seed ^= std::hash<DIS_TYPE>{}(p.dis) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
            return seed;
        }
    };

    // 自定义相等比较函数
    template<typename T>
    class PointEqual {
    public:
        bool operator()(const Point<T> &lhs, const Point<T> &rhs) const {
            return lhs.oId == rhs.oId && lhs.keyObject == rhs.keyObject && lhs.dis == rhs.dis;
        }
    };

    struct PointPair {
        OID_TYPE index1, index2;
        DIS_TYPE dis;

        PointPair(OID_TYPE i1, OID_TYPE i2, DIS_TYPE dist) : index1(i1), index2(i2), dis(dist) {}

        bool operator>(const PointPair &other) const {
            return dis > other.dis;
        }

        bool operator<(const PointPair &other) const {
            return dis < other.dis;
        }
    };
}